﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Cyss.Core
{

    /// <summary>
    /// 
    /// </summary>
    public static class TypeExtensions
    {

        /// <summary>
        /// 截取某个字符后的所有字符
        /// </summary>
        /// <returns></returns>
        public static string SubstringRight(this string value, string p)
        {
            if (value==null)
            {
                return value;
            }
            if (value.IndexOf(p)<0)
            {
                return string.Empty;
            }
            int i = value.IndexOf(p)+p.Length;
            return value.Substring(i).Trim();
        }

        /// <summary>
        /// 截取某个字符前的所有字符
        /// </summary>
        /// <returns></returns>
        public static string SubstringLeft(this string value, string p)
        {
            if (value==null)
            {
                return value;
            }
            if (value.IndexOf(p)<0)
            {
                return string.Empty;
            }
            int i = value.IndexOf(p);
            return value.Substring(0, i).Trim();
        }

        /// <summary>
        /// 去掉所有空格
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string TrimAll(this string value)
        {
            if (value==null)
            {
                return value;
            }
            return value.Replace(" ", "").Trim();
        }

        /// <summary>
        /// 去掉所有空格(字符中间有多个空格的时候保留一个空格)
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string TrimAll2(this string value)
        {
            if (value==null)
            {
                return value;
            }
            return Regex.Replace(value, @"[\s+]{2,}", " ");
        }

        /// <summary>
        /// 生成随机数
        /// </summary>
        /// <param name="digits"></param>
        /// <returns></returns>
        public static string GenerateRandom(int digits = 6)
        {
            Random random = new Random();
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 1; i<=6; i++)
            {
                stringBuilder.Append(random.Next(1, 9));
            }
            return stringBuilder.ToString();
        }

        /// <summary>
        /// 自动前置补位
        /// </summary>
        /// <param name="value"></param>
        /// <param name="Symbol">占位符号</param>
        /// <param name="FillingCount">总位数，value不够补差位</param>
        /// <returns></returns>
        public static string LeftFilling(this string value, string Symbol, int TotalFillingCount)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                value=string.Empty;
            }
            string str = string.Empty;
            for (int i = 0; i<TotalFillingCount-value.Length; i++)
            {
                str+=Symbol;
            }
            return str+value;
        }

        /// <summary>
        /// 自动前置补位
        /// </summary>
        /// <param name="arrs"></param>
        /// <param name="Symbol">占位符号</param>
        /// <param name="FillingCount">总位数，value不够补差位</param>
        /// <returns></returns>
        public static IEnumerable<string> LeftFilling(this IEnumerable<string> arrs, string Symbol, int TotalFillingCount)
        {
            List<string> list = new List<string>();
            foreach (var item in arrs)
            {
                list.Add(item.LeftFilling(Symbol, TotalFillingCount));
            }
            return list;
        }

        /// <summary>
        /// 取左边的字符串
        /// </summary>
        /// <param name="value"></param>
        /// <param name="lenght"></param>
        /// <returns></returns>
        public static string Left(this string value, int lenght)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                return string.Empty;
            }
            if (value.Length < lenght)
            {
                return value;
            }
            return value.Substring(0, lenght);
        }

        /// <summary>
        /// 删除邮编字符串
        /// </summary>
        /// <param name="value"></param>
        /// <param name="lenght"></param>
        /// <returns></returns>
        public static string DeleteRight(this string value, int lenght)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                return string.Empty;
            }
            if (value.Length <= lenght)
            {
                return string.Empty;
            }
            return value.Substring(0, value.Length- lenght);
        }

        /// <summary>
        /// 取右边的字符串
        /// </summary>
        /// <param name="value"></param>
        /// <param name="lenght"></param>
        /// <returns></returns>
        public static string Right(this string value, int lenght)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                return string.Empty;
            }
            if (value.Length < lenght)
            {
                return value;
            }
            var start = value.Length - lenght;
            if (start <= 0) start = 0;
            return value.Substring(start);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <param name="separators">默认逗号间隔</param>
        /// <returns></returns>
        public static IEnumerable<T> Split<T>(this string value, params string[] separators)
        {
            if (separators == null || separators.Count() <= 0)
            {
                separators = new string[] { "," };
            }

            if (string.IsNullOrWhiteSpace(value))
            {
                return new List<T>();
            }
            return value.Split(separators, StringSplitOptions.RemoveEmptyEntries).Select(x => { return Convert.ChangeType(x.Trim(), typeof(T)); }).Cast<T>().ToList();
        }

        /// <summary>
        /// 判断两个字符串是否相等，不区分大小写，
        /// </summary>
        /// <param name="str"></param>
        /// <param name="str2"></param>
        /// <returns></returns>
        public static bool IsEquals(this string str, string str2)
        {
            if (str == null) str = string.Empty;
            if (str2 == null) str2 = string.Empty;
            if (str.Trim().ToLower() == str2.Trim().ToLower())
            {
                return true;
            }
            return false;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="theType"></param>
        /// <returns></returns>
        public static bool IsNullableType(this Type theType)
        {
            return (theType.IsGenericType && theType.
              GetGenericTypeDefinition().Equals
              (typeof(Nullable<>)));
        }

        /// <summary>
        /// 获取类型  TypeCode
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static TypeCode GetTypeCode(this Type type)
        {
            if (type==typeof(DateTime) || type==typeof(DateTime?))
            {
                return TypeCode.DateTime;
            }
            if (type==typeof(string))
            {
                return TypeCode.String;
            }
            if (type==typeof(Int16) || type==typeof(Int16?))
            {
                return TypeCode.Int16;
            }
            if (type==typeof(Int32) || type==typeof(Int32?))
            {
                return TypeCode.Int32;
            }
            if (type==typeof(Int64) || type==typeof(Int64?))
            {
                return TypeCode.Int64;
            }
            if (type==typeof(bool) || type==typeof(bool?))
            {
                return TypeCode.Boolean;
            }
            if (type==typeof(decimal) || type==typeof(decimal?))
            {
                return TypeCode.Decimal;
            }
            if (type==typeof(double) || type==typeof(double?))
            {
                return TypeCode.Double;
            }
            if (type==typeof(float) || type==typeof(float?))
            {
                return TypeCode.Int16;
            }
            return TypeCode.Empty;
        }

        /// <summary>
        /// 将字符串转成Byte
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Byte[] ToBytes(this string data)
        {
            System.Text.UTF8Encoding uTF8 = new System.Text.UTF8Encoding();
            return uTF8.GetBytes(data);
        }

        /// <summary>
        /// 将byte转成字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToString(this byte[] bytes)
        {
            System.Text.UTF8Encoding uTF8 = new System.Text.UTF8Encoding();
            return uTF8.GetString(bytes);
        }

        /// <summary>
        /// 首字母小写
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ToFirstLower(this string str)
        {
            if (string.IsNullOrWhiteSpace(str))
            {
                return string.Empty;
            }
            return str[0].ToString().ToLower() + str.Substring(1, str.Length - 1);
        }

        /// <summary>
        /// 是否全部为字母
        /// </summary>
        /// <param name="inputString"></param>
        /// <returns></returns>
        public static bool ISAllLetter(this string inputString)
        {
            if (string.IsNullOrEmpty(inputString))
            {
                return false;
            }
            return Regex.IsMatch(inputString, @"[^0-9]+$", RegexOptions.Singleline);
        }

        /// <summary>
        /// 获取datarow col 的值 空值不会报异常
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="colName"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static object ToTryValue<T>(this DataRow row, string colName, T defaultValue)
        {
            if (!row.Table.Columns.Contains(colName))
            {
                return defaultValue;
            }
            var value = row[colName].ToString();
            T ret = (T)Convert.ChangeType(defaultValue, typeof(T));
            try
            {
                ret = (T)Convert.ChangeType(value, typeof(T));
            }
            catch
            {

            }
            return ret;
        }

        /// <summary>
        /// 获取datarow col 的值 不会报异常
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="colName"></param>
        /// <returns></returns>
        public static T ToTryValue<T>(this DataRow row, string colName)
        {
            if (!row.Table.Columns.Contains(colName))
            {
                return default(T);
            }
            var value = row[colName].ToString();
            try
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
            catch
            {
                return default(T);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static Type GetListItemType<T>(this IEnumerable<T> list)
        {
            return list.GetType().GetGenericArguments().LastOrDefault();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToNullString(this object obj)
        {
            if (obj == null)
            {
                return "null";
            }
            return obj.ToString();
        }

        /// <summary>
        /// 是否是美国电话号码
        /// </summary>
        /// <param name="Number"></param>
        /// <returns></returns>
        public static bool IsUSPhoneNumber(this string Number)
        {
            return Regex.IsMatch(Number, @"/^(1?|(1\-)?)\d{10,12}$/");
        }

        /// <summary>
        /// 字符串压缩
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ZipString(this string value)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                return value;
            }
            byte[] byteArray = new byte[value.Length];

            int index = 0;

            foreach (char item in value.ToCharArray())
            {
                byteArray[index++] = (byte)item;
            }

            MemoryStream ms = new MemoryStream();
            GZipStream zipStream = new GZipStream(ms, CompressionMode.Compress);

            // Compress
            zipStream.Write(byteArray, 0, byteArray.Length);

            zipStream.Close();

            byteArray = ms.ToArray();
            StringBuilder builder = new StringBuilder(byteArray.Length);

            foreach (byte item in byteArray)
            {
                builder.Append((char)item);
            }

            ms.Close();
            zipStream.Close();
            ms.Dispose();
            zipStream.Dispose();

            return builder.ToString();
        }

        /// <summary>
        /// 字符串解压
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string UnZipString(this string value)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                return value;
            }
            byte[] byteArray = new byte[value.Length];
            int index = 0;
            foreach (char item in value.ToCharArray())
            {
                byteArray[index++] = (byte)item;
            }

            // Decompress
            MemoryStream ms = new MemoryStream(byteArray);
            GZipStream zipStream = new GZipStream(ms, CompressionMode.Decompress);
            StreamReader reader = new StreamReader(zipStream);

            string builder = reader.ReadToEnd();

            ms.Close();
            zipStream.Close();
            ms.Dispose();
            zipStream.Dispose();
            reader.Close();
            reader.Dispose();

            return builder;
        }

        /// <summary> 
        /// 将 Stream 转成 byte[] 
        /// </summary> 
        public static byte[] ToBytes(this Stream stream)
        {
            if (stream == null) return null;
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);

            // 设置当前流的位置为流的开始 
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }

        /// <summary> 
        /// 将 byte[] 转成 Stream 
        /// </summary> 
        public static Stream ToStream(this byte[] bytes)
        {
            if (bytes == null) return null;
            Stream stream = new MemoryStream(bytes);
            return stream;
        }
        /// <summary> 
        /// 将 byte[] 转成 Stream 
        /// </summary> 
        public static MemoryStream ToMemoryStream(this byte[] bytes)
        {
            if (bytes == null) return null;
            MemoryStream stream = new MemoryStream(bytes);
            return stream;
        }

        /// <summary>
        /// 类型是否实现某个基类
        /// </summary>
        /// <typeparam name="type"></typeparam>
        /// <returns></returns>
        public static bool IsImplementBaseType<T>(this Type type)
        {
            if (type.BaseType==null)
            {
                return false;
            }
            if (type.BaseType==typeof(T))
            {
                return true;
            }
            return IsImplementBaseType<T>(type.BaseType);
        }

        /// <summary>
        /// 判断指定的类型 <paramref name="type"/> 是否是指定泛型类型的子类型，或实现了指定泛型接口。
        /// </summary>
        /// <param name="type">需要测试的类型。</param>
        /// <param name="generic">泛型接口类型，传入 typeof(IXxx<>)</param>
        /// <returns>如果是泛型接口的子类型，则返回 true，否则返回 false。</returns>
        public static bool HasImplementedRawGeneric(this Type type, Type generic)
        {
            if (type == null) throw new ArgumentNullException(nameof(type));
            if (generic == null) throw new ArgumentNullException(nameof(generic));

            // 测试接口。
            var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
            if (isTheRawGenericType) return true;

            // 测试类型。
            while (type != null && type != typeof(object))
            {
                isTheRawGenericType = IsTheRawGenericType(type);
                if (isTheRawGenericType) return true;
                type = type.BaseType;
            }

            // 没有找到任何匹配的接口或类型。
            return false;

            // 测试某个类型是否是指定的原始接口。
            bool IsTheRawGenericType(Type test)
            => generic == (test.IsGenericType ? test.GetGenericTypeDefinition() : test);
        }

        public static bool IsInt(this string value)
        {
            int vsNum;
            return Int32.TryParse(value, out vsNum);
        }

        public static bool IsDouble(this string value)
        {
            double vsNum;
            return double.TryParse(value, out vsNum);
        }


        /// <summary>
        /// 格式化参数
        /// </summary>
        /// <param name="pars"></param>
        /// <returns></returns>
        public static string FormatParameters(this IEnumerable<object> Parameters)
        {
            string strs = string.Empty;
            foreach (var par in Parameters)
            {
                if (!string.IsNullOrWhiteSpace(strs))
                {
                    strs+="-";
                }
                if (par==null)
                {
                    strs+="null";
                    continue;
                }
                if (par.GetType()==typeof(DateTime) || par.GetType()==typeof(DateTime?))
                {
                    strs+=((DateTime)par).ToFileTimeUtc().ToString();
                    continue;
                }
                if (par.GetType()==typeof(string))
                {
                    strs+=par.ToString();
                    continue;
                }
                if (par.GetType().IsValueType)
                {
                    strs+=par.ToString();
                    continue;
                }
                else
                {
                    strs+=EncryptHelper.MD5Encrypt(par.ToSerializeObject());
                    continue;
                }
            }
            return strs;
        }
    }
}
